#!/usr/bin/env python
#-*- coding: utf-8 -*-

#------------------------------------------------------------------------------
"""
# 时间：2022年07月16日15:06:05
# 名称：Cava测试云服务开放平台客户端 CavaOpenClient
# 功能：Cava测试云服务开放平台客户端
# 版本：V1.0.1
# @author：yezhibin
改动：
1、2022年07月16日15:06:13 新建

注意事项:
1、打包使用pyinstaller 3.5
2、requests库使用2.10
3、robotframework-requests库使用0.4.1
"""

#------------------------------------------------------------------------------

from http.client import REQUEST_URI_TOO_LONG
from lib2to3.pgen2.tokenize import TokenError
import sys
import os
import getopt
import threading
import io
import datetime
import time
import platform
import json
from RequestsLibrary import RequestsLibrary
import random
import hashlib
import string
from lxml import etree
from logger import *

sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8')


class CavaOpenClient:

    def __init__(self):
        self.server_ip = "139.198.176.69"
        self.http_port = 9030
        self.username = ""
        self.password = ""
        self.server_waittime = 1
        self.server_trytimes = 3
        
        self.app_id = ""
        self.app_secret = ""
        self.access_token = self.load_token()

        self.task_name = ""
        self.task_dir = ""
        self.task_data = ""
        self.force_upload = False
        self.mail_addr = ""
        self.sys_type = ""
        self.block_pass_mail = False
        self.task_id = ""

        self.re_test_data_path = ""     # 上传的测试数据在云端的保存路径
        self.exit = False

        self.alias = "CavaOpenClient"
        self.url = ""
        self.req = RequestsLibrary()
        self.headers = {}

        file_path = "./config.xml"
        c = len(sys.argv)
        #命令行参数解析
        if c > 1:
            if sys.argv[1].find("-") != -1:  # 编译器中调试时索引改为sys.argv[0]，正式为sys.argv[1]
                opts, args = getopt.getopt(sys.argv[1:], "hc:", ["help", "config="])
                for op, value in opts:
                    if op == "-c" or op == "--config":
                        file_path = value
                    elif op == "-h" or op == "--help":
                        self.usage()
                        self.exit = True
                        sys.exit()
                    else:
                        info("[ERR] err: params invalid")
                        self.exit = True
                        sys.exit()

        self.read_config_and_update(file_path)
        
        self.url = "http://%s:%d" %(self.server_ip, self.http_port)
        self.req.create_session(self.alias, self.url, self.headers, None, None, self.server_waittime, None, False, 0, self.server_trytimes)


    def clean(self):
        self.req.delete_all_sessions()


    def get_exit(self):
        return self.exit

    def set_exit(self, exit):
        self.exit = exit

    def usage(self):
        help_txt = ("CavaOpenClient 使用帮助V1.0\n"
                    "目前支持的参数有(均为可选参数)：\n"
                    "    -c, --config： xml配置文件路径, 包含文件名\n"
                    "    -h, --help:   显示使用帮助\n"
                    "    最新版本 : CavaClient-V1.0.1-build 20220716 %s\n"
                    "    最后修改时间 : s2022年07月16日15:22:53\n"
                    ) %(platform.system())
        print(help_txt)


    def read_config_and_update(self, file_path="./config.xml"):
        cfg_file_abs_path = file_path
        if os.path.exists(cfg_file_abs_path):
            try:
                bool_list = [False, True]
                fin = open(cfg_file_abs_path, "r", encoding='utf-8')
                contents = fin.read()
                fin.close()
                page = etree.HTML(contents.encode("utf-8"))     # tuf-8解码后再加载

                self.server_ip = str(page.xpath("//config/server/ip/text()")[0])
                self.http_port = int(page.xpath("//config/server/httpport/text()")[0])
                self.username = str(page.xpath("//config/server/username/text()")[0])
                self.password = str(page.xpath("//config/server/password/text()")[0])
                self.server_waittime = float(page.xpath("//config/server/waittime/text()")[0])
                self.server_trytimes = int(page.xpath("//config/server/trytimes/text()")[0])

                self.app_id = str(page.xpath("//config/auth/app_id/text()")[0])
                self.app_secret = str(page.xpath("//config/auth/app_secret/text()")[0])

                self.task_name = str(page.xpath("//config/task/name/text()")[0])
                self.task_dir = str(page.xpath("//config/task/dir/text()")[0])
                self.task_data = str(page.xpath("//config/task/data/path/text()")[0])
                self.force_upload = bool_list[int(page.xpath("//config/task/data/force_upload/text()")[0])]
                self.mail_addr = str(page.xpath("//config/task/mail_addr/text()")[0])
                self.sys_type = str(page.xpath("//config/task/sys_type/text()")[0])
                self.block_pass_mail = bool_list[int(page.xpath("//config/task/block_pass_mail/text()")[0])]

            except Exception as ex:
                opt_info = "[ERR] %s: %s" %(Exception, ex)
                info(opt_info)
        else:
            info("[ERR] err: %s not exist!" %cfg_file_abs_path)
            self.exit = True
            sys.exit()


    def load_token(self):
        file_pth = ("./access_token")
        if os.path.exists(file_pth) is False:
            return ""
        fin = open(file_pth, "r")
        tmp = fin.read()
        token = tmp.strip()
        fin.close()
        return token


    def save_token(self, token):
        file_pth = ("./access_token")
        if os.path.exists(file_pth):
            os.remove(file_pth)
        fout = open(file_pth, "w")
        fout.write("%s\r\n" %token)
        fout.close()


    def preck_token(self):
        uri = "/notice?accessToken=%s" %self.access_token
        resp = self.req.get_request(self.alias, uri, timeout=self.server_waittime)
        ret_data_dict = json.loads(resp.content.decode("utf-8"))

        if "error" in ret_data_dict.keys():
            info("[ERR] recv response: %s, accessToken: %s" %(ret_data_dict["error"]["message"], self.access_token))
            return False
        return True


    def refresh_token(self):
        uri = "/api/token/get?appID=%s&appSecret=%s" %(self.app_id, self.app_secret)
        resp = self.req.get_request(self.alias, uri, timeout=self.server_waittime)
        ret_data_dict = json.loads(resp.content.decode("utf-8"))

        if "error" in ret_data_dict.keys():
            info("[ERR] recv response contains err message: %s" %ret_data_dict["error"]["message"])
            self.access_token = ""
        elif "data" in ret_data_dict.keys():
            self.access_token = ret_data_dict["data"]["accessToken"]
            self.save_token(self.access_token)
            info("[WARN] refresh accessToken: %s" %self.access_token)


    def upload_file_V2(self, forece_update="FALSE"):
        url = "http://%s:%d" %(self.server_ip, self.http_port)

        random_data = ''.join(random.sample(string.ascii_letters + string.digits, 32))
        now_time_obj = datetime.datetime.now()
        now_time_str = now_time_obj.strftime("%Y-%m-%dT%H:%M:%SZ")
        plain_data = "%s%s%s%s" %(self.username, self.password, random_data, now_time_str)

        m = hashlib.sha256()
        m.update(plain_data.encode("utf-8"))
        digest = m.hexdigest()
        
        tmp_dict = {
            "FORCE-UPLOAD":forece_update
        }

        test_data_path = self.task_data   # 配置的待上传的测试文件路径
        if os.path.exists(test_data_path) is False:
            return
        files = {"file": open(test_data_path, "rb")}
        
        uri = "/cava3/upload?accessToken=%s" %self.access_token
        resp = self.req.post_request(self.alias, uri, files=files, headers=tmp_dict, timeout=self.server_waittime)

        ret_data_dict = json.loads(resp.content.decode("utf-8"))
        if ret_data_dict.get("data"):
            ret_info = ret_data_dict["data"]
            if ret_info.find("upload succeed") != -1:
                pos = ret_info.find("path:")
                self.re_test_data_path = ret_info[pos+5:]
                opt_info = "[INFO] %s upload succeed, save path: %s" %(test_data_path, self.re_test_data_path)
                info(opt_info)
                return
        opt_info = "%s upload failed, err: %s" %(test_data_path, ret_info)
        info(opt_info)

        ret_data_dict = json.loads(resp.content.decode("utf-8"))


    def upload_file(self):
        if self.preck_token() is False:
            self.refresh_token()
   
        url = "http://%s:%d" %(self.server_ip, self.http_port)
        random_data = ''.join(random.sample(string.ascii_letters + string.digits, 32))
        now_time_obj = datetime.datetime.now()
        now_time_str = now_time_obj.strftime("%Y-%m-%dT%H:%M:%SZ")
        plain_data = "%s%s%s%s" %(self.username, self.password, random_data, now_time_str)

        m = hashlib.sha256()
        m.update(plain_data.encode("utf-8"))
        digest = m.hexdigest()
        
        tmp_dict = {
            "FORCE-UPLOAD":"FALSE"
        }

        test_data_path = self.task_data   # 配置的待上传的测试文件路径
        if os.path.exists(test_data_path) is False:
            return
        files = {"file": open(test_data_path, "rb")}
        
        uri = "/cava3/upload?accessToken=%s" %self.access_token
        resp = self.req.post_request(self.alias, uri, files=files, headers=tmp_dict, timeout=self.server_waittime)

        ret_data_dict = json.loads(resp.content.decode("utf-8"))
        if ret_data_dict.get("data"):
            ret_info = ret_data_dict["data"]
            if ret_info.find("upload succeed") != -1:
                pos = ret_info.find("path:")
                self.re_test_data_path = ret_info[pos+5:]
                opt_info = "[INFO] %s upload succeed, save path: %s" %(test_data_path, self.re_test_data_path)
                info(opt_info)
                return
            elif ret_info.find("file exist") != -1:
                if self.force_upload is True:  # 通过if 语句来判断用户选择的结果
                    self.upload_file_V2("TRUE")
                    return
                else:
                    opt_info = "[WARN] dest path exist the same name file, user cancel upload"
                    info(opt_info)
                    return
        opt_info = "[ERR] %s upload failed, err: %s" %(test_data_path, ret_info)
        info(opt_info)


    def test_req(self):
        if self.preck_token() is False:
            self.refresh_token()    

        data_dic = {}
        data_dic["taskDir"] = self.task_dir
        data_dic["taskName"] = self.task_name
        data_dic["testData"] = self.re_test_data_path   # http://192.168.0.136:9000/cava3/upload/DeviceList.xls
        data_dic["mailAddr"] = self.mail_addr
        data_dic["blockPassMail"] = self.block_pass_mail
        data_dic["sysType"] = self.sys_type
        data_dic_str = json.dumps(data_dic)
        info("[INFO] test req data: %s" %data_dic_str)
        opt_info = "[INFO] send task request, taskName=%s, blockPassMail=%d" %(data_dic["taskName"], data_dic["blockPassMail"])
        info(opt_info)

        tmp_dict = {
            "Content-Type":"application/json",
            }

        uri = "/api/task/create?accessToken=%s" %self.access_token
        resp = self.req.post_request(self.alias, uri, data=data_dic_str, headers=tmp_dict, timeout=self.server_waittime)
        ret_data_dict = json.loads(resp.content.decode("utf-8"))
        try:
            self.task_id = ret_data_dict["data"]["task_id"]
            info("[INFO] parse from resp, task_id: %s" %self.task_id)
        except Exception as  ex:
            info("[ERR] %s: %s" %(Exception, ex))
            self.task_id = ""

    def query_task_report(self):
        if self.preck_token() is False:
            self.refresh_token()
        
        uri = "/cava3/task/%s?accessToken=%s" %(self.task_id, self.access_token)
        resp = self.req.get_request(self.alias, uri, timeout=self.server_waittime)
        ret_data_dict = json.loads(resp.content.decode("utf-8"))
        task_list = ret_data_dict["data"]["task"]
        if len(task_list) == 0:
            return False

        task = task_list[0]
        if task["status"] != "completed":
            return False

        info("[INFO] get task report, task_id: %s, htmlPath: %s, passRate: %s" %(self.task_id, 
            task["metadata"]["htmlPath"], 
            task["metadata"]["passRate"]))
        return True


if __name__ == "__main__":
    app = CavaOpenClient()
    if app.get_exit() is False:
        app.upload_file()
        app.test_req()
    while app.get_exit() is False:
        if app.query_task_report():
            break
        time.sleep(3)
    app.clean()